 /*******************************************************************************
  * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  * Gunnar Wagenknecht - some contributions (bug fixes and enhancements)
  *******************************************************************************/
 package org.eclipse.ui.internal.presentations;

 import java.util.ArrayList ;
 import java.util.Iterator ;
 import java.util.List ;

 import org.eclipse.core.runtime.Assert;
 import org.eclipse.jface.action.GroupMarker;
 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.action.Separator;
 import org.eclipse.jface.util.Geometry;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.CLabel;
 import org.eclipse.swt.events.DisposeEvent;
 import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.events.MouseAdapter;
 import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.ShellAdapter;
 import org.eclipse.swt.events.ShellEvent;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.ToolBar;
 import org.eclipse.swt.widgets.ToolItem;
 import org.eclipse.ui.IMemento;
 import org.eclipse.ui.IPropertyListener;
 import org.eclipse.ui.internal.IWorkbenchConstants;
 import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
 import org.eclipse.ui.internal.WorkbenchImages;
 import org.eclipse.ui.internal.dnd.DragUtil;
 import org.eclipse.ui.internal.presentations.r21.R21Colors;
 import org.eclipse.ui.internal.presentations.r21.R21PresentationMessages;
 import org.eclipse.ui.internal.presentations.r21.widgets.CTabItem;
 import org.eclipse.ui.internal.presentations.r21.widgets.R21PaneFolder;
 import org.eclipse.ui.internal.util.Util;
 import org.eclipse.ui.presentations.IPartMenu;
 import org.eclipse.ui.presentations.IPresentablePart;
 import org.eclipse.ui.presentations.IPresentationSerializer;
 import org.eclipse.ui.presentations.IStackPresentationSite;
 import org.eclipse.ui.presentations.PresentationUtil;
 import org.eclipse.ui.presentations.StackDropResult;
 import org.eclipse.ui.presentations.StackPresentation;

 /**
  * Base class for StackPresentations that display IPresentableParts in a
  * CTabFolder.
  *
  * @since 3.0
  */
 public class R21BasicStackPresentation extends StackPresentation {

     private R21PaneFolder paneFolder;

     private IPresentablePart current;

     private boolean activeState = false;

     private MenuManager systemMenuManager = new MenuManager();

     private CLabel titleLabel;

     private boolean shellActive = true;

     private final static String TAB_DATA = R21BasicStackPresentation.class
             .getName()
             + ".partId"; //$NON-NLS-1$

     // private PaneFolderButtonListener buttonListener = new
 // PaneFolderButtonListener() {
 // public void stateButtonPressed(int buttonId) {
 // getSite().setState(buttonId);
 // }
 //
 // public void closeButtonPressed(CTabItem item) {
 // IPresentablePart part = getPartForTab(item);
 //
 // getSite().close(part);
 // }
 // };
 //
 private MouseListener mouseListener = new MouseAdapter() {
         public void mouseDown(MouseEvent e) {
             if (e.widget instanceof Control) {
                 Control ctrl = (Control) e.widget;
                 Point globalPos = ctrl.toDisplay(new Point(e.x, e.y));

                 // PR#1GDEZ25 - If selection will change in mouse up ignore
 // mouse down.
 // Else, set focus.
 CTabItem newItem = paneFolder.getItem(paneFolder.getControl()
                         .toControl(globalPos));
                 if (newItem != null) {
                     CTabItem oldItem = paneFolder.getSelection();
                     if (newItem != oldItem) {
                         return;
                     }
                 }
                 if (current != null) {
                     current.setFocus();
                 }
             }
         }

         public void mouseDoubleClick(MouseEvent e) {
             if (getSite().getState() == IStackPresentationSite.STATE_MAXIMIZED) {
                 getSite().setState(IStackPresentationSite.STATE_RESTORED);
             } else {
                 getSite().setState(IStackPresentationSite.STATE_MAXIMIZED);
             }
         }
     };

     private MouseListener titleMouseListener = new MouseAdapter() {
         public void mouseDown(MouseEvent e) {
             if (e.widget instanceof Control) {
                 Control ctrl = (Control) e.widget;
                 Point globalPos = ctrl.toDisplay(new Point(0, titleLabel
                         .getBounds().height));

                 if ((e.button == 1) && overImage(e.x)) {
                     showSystemMenu(globalPos);
                 }
             }
         }
     };

     private Listener menuListener = new Listener() {
         /*
          * (non-Javadoc)
          *
          * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
          */
         public void handleEvent(Event event) {
             Point pos = new Point(event.x, event.y);

             showSystemMenu(pos);
         }
     };

     private Listener dragListener = new Listener() {
         public void handleEvent(Event event) {

             Point localPos = new Point(event.x, event.y);
             CTabItem tabUnderPointer = paneFolder.getItem(localPos);

             // Drags on the title area drag the selected part only
 if (tabUnderPointer == null) {
                 if (paneFolder.getTabPosition() == SWT.BOTTOM
                         && localPos.y < paneFolder.getControl().getBounds().height
                                 - paneFolder.getTabHeight()) {
                     tabUnderPointer = paneFolder.getSelection();
                 } else if (paneFolder.getTabPosition() == SWT.TOP
                         && localPos.y > paneFolder.getTabHeight()) {
                     tabUnderPointer = paneFolder.getSelection();
                 }
             }

             // Not in a tab, not in a title area, must be dragging the whole
 // stack
 if (tabUnderPointer == null) {
                 getSite().dragStart(
                         paneFolder.getControl().toDisplay(localPos), false);
                 return;
             }

             IPresentablePart part = getPartForTab(tabUnderPointer);

             if (getSite().isPartMoveable(part)) {
                 getSite().dragStart(part,
                         paneFolder.getControl().toDisplay(localPos), false);
             }
         }
     };

     private Listener selectionListener = new Listener() {
         public void handleEvent(Event e) {
             IPresentablePart item = getPartForTab((CTabItem) e.item);

             if (item != null) {
                 getSite().selectPart(item);
             }
         }
     };

     private Listener resizeListener = new Listener() {
         public void handleEvent(Event e) {
             setControlSize();
         }
     };

     private IPropertyListener childPropertyChangeListener = new IPropertyListener() {
         public void propertyChanged(Object source, int property) {
             if (source instanceof IPresentablePart) {
                 IPresentablePart part = (IPresentablePart) source;
                 childPropertyChanged(part, property);
             }
         }
     };

     private DisposeListener tabDisposeListener = new DisposeListener() {
         public void widgetDisposed(DisposeEvent e) {
             if (e.widget instanceof CTabItem) {
                 CTabItem item = (CTabItem) e.widget;

                 IPresentablePart part = getPartForTab(item);

                 part.removePropertyListener(childPropertyChangeListener);
             }
         }
     };

     /** the shell listener for upgrading the gradient */
     private ShellAdapter shellListener = new ShellAdapter() {

         public void shellActivated(ShellEvent event) {
             shellActive = true;
             updateGradient();
         }

         public void shellDeactivated(ShellEvent event) {
             shellActive = false;
             updateGradient();
         }
     };

     private ToolBar viewToolBar;

     private ToolItem pullDownButton;

     private ToolItem closeButton;

     public R21BasicStackPresentation(R21PaneFolder control,
             IStackPresentationSite stackSite) {
         super(stackSite);
         paneFolder = control;

         shellActive = paneFolder.getControl().getShell().equals(
                 control.getControl().getDisplay().getActiveShell());

         // tabFolder.setMinimizeVisible(stackSite.supportsState(IStackPresentationSite.STATE_MINIMIZED));
 // tabFolder.setMaximizeVisible(stackSite.supportsState(IStackPresentationSite.STATE_MAXIMIZED));
 //
 titleLabel = new CLabel(paneFolder.getControl(), SWT.SHADOW_NONE);
         titleLabel.setVisible(false);
         titleLabel.moveAbove(null);
         titleLabel.addMouseListener(titleMouseListener);
         titleLabel.addMouseListener(mouseListener);
         titleLabel.addListener(SWT.MenuDetect, menuListener);
         PresentationUtil.addDragListener(titleLabel, dragListener);

         // ColorSchemeService.setViewTitleFont(this, titleLabel);

         viewToolBar = new ToolBar(control.getControl(), SWT.HORIZONTAL
                 | SWT.FLAT);
         viewToolBar.moveAbove(null);

         pullDownButton = new ToolItem(viewToolBar, SWT.PUSH);
         // Image img =
 // WorkbenchImages.getImage(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU);
 Image hoverImage = WorkbenchImages
                 .getImage(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU);
         pullDownButton.setDisabledImage(null); // TODO: comment this out?
 // PR#1GE56QT - Avoid creation of unnecessary image.
 pullDownButton.setImage(hoverImage);
         pullDownButton.setToolTipText(R21PresentationMessages
                 .getString("BasicStackPresentation.menu.tooltip")); //$NON-NLS-1$
 pullDownButton.addSelectionListener(new SelectionAdapter() {
             public void widgetSelected(SelectionEvent e) {
                 showPaneMenu();
             }
         });

         // listener to switch between visible tabItems
 paneFolder.getControl().addListener(SWT.Selection, selectionListener);

         // listener to resize visible components
 paneFolder.getControl().addListener(SWT.Resize, resizeListener);

         // listen for mouse down on tab to set focus.
 paneFolder.getControl().addMouseListener(mouseListener);

         paneFolder.getControl().addListener(SWT.MenuDetect, menuListener);

         // tabFolder.addButtonListener(buttonListener);

         PresentationUtil.addDragListener(paneFolder.getControl(), dragListener);

         // add the shell listener to track shell activations
 // TODO: check if workaround can be removed (see bug 55458)
 paneFolder.getControl().getShell().addShellListener(shellListener);

         // Uncomment to allow dragging from the title label
 // PresentationUtil.addDragListener(titleLabel, new Listener() {
 // public void handleEvent(Event event) {
 // if (layout.isTrimOnTop()) {
 // Point localPos = new Point(event.x, event.y);
 // getSite().dragStart(titleLabel.toDisplay(localPos), false);
 // }
 // }
 // });

         // // Compute the tab height
 // int tabHeight = viewToolBar.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
 //
 // // Enforce a minimum tab height
 // if (tabHeight < 20) {
 // tabHeight = 20;
 // }
 // paneFolder.setTabHeight(tabHeight);
 //
 populateSystemMenu(systemMenuManager);
     }

     /*
      * Return true if <code>x</code> is over the label image.
      */
     private boolean overImage(int x) {
         return x < titleLabel.getImage().getBounds().width;
     }

     /**
      * @param systemMenuManager
      */
     private void populateSystemMenu(IMenuManager systemMenuManager) {

         systemMenuManager.add(new GroupMarker("misc")); //$NON-NLS-1$
 systemMenuManager.add(new GroupMarker("restore")); //$NON-NLS-1$
 systemMenuManager.add(new UpdatingActionContributionItem(
                 new SystemMenuRestore(getSite())));

         systemMenuManager.add(new SystemMenuMove(getSite(), getPaneName()));
         systemMenuManager.add(new GroupMarker("size")); //$NON-NLS-1$
 systemMenuManager.add(new GroupMarker("state")); //$NON-NLS-1$
 systemMenuManager.add(new UpdatingActionContributionItem(
                 new SystemMenuMinimize(getSite())));

         systemMenuManager.add(new UpdatingActionContributionItem(
                 new SystemMenuMaximize(getSite())));
         systemMenuManager.add(new Separator("close")); //$NON-NLS-1$
 systemMenuManager.add(new UpdatingActionContributionItem(
                 new SystemMenuClose(getSite())));

         getSite().addSystemActions(systemMenuManager);
     }

     protected String getPaneName() {
         return R21PresentationMessages.getString("BasicStackPresentation.pane"); //$NON-NLS-1$
 }

     /**
      * Displays the view menu as a popup
      */
     public void showPaneMenu() {
         IPartMenu menu = getPartMenu();

         if (menu != null) {
             Rectangle bounds = DragUtil.getDisplayBounds(viewToolBar);
             menu.showMenu(new Point(bounds.x, bounds.y + bounds.height));
         }
     }

     /**
      * Returns the currently selected part, or <code>null</code>.
      *
      * @return the currently selected part, or <code>null</code>
      */
     protected IPresentablePart getCurrent() {
         return current;
     }

     /**
      * Returns the index of the tab for the given part, or returns
      * tabFolder.getItemCount() if there is no such tab.
      *
      * @param part
      * part being searched for
      * @return the index of the tab for the given part, or the number of tabs if
      * there is no such tab
      */
     private final int indexOf(IPresentablePart part) {
         if (part == null) {
             return paneFolder.getItemCount();
         }

         CTabItem[] items = paneFolder.getItems();

         for (int idx = 0; idx < items.length; idx++) {
             IPresentablePart tabPart = getPartForTab(items[idx]);

             if (part == tabPart) {
                 return idx;
             }
         }

         return items.length;
     }

     /**
      * Returns the tab for the given part, or null if there is no such tab
      *
      * @param part
      * the part being searched for
      * @return the tab for the given part, or null if there is no such tab
      */
     protected final CTabItem getTab(IPresentablePart part) {
         CTabItem[] items = paneFolder.getItems();

         int idx = indexOf(part);

         if (idx < items.length) {
             return items[idx];
         }

         return null;
     }

     /**
      * @param part
      * @param property
      */
     protected void childPropertyChanged(IPresentablePart part, int property) {

         CTabItem tab = getTab(part);
         initTab(tab, part);

         switch (property) {
         case IPresentablePart.PROP_BUSY:
             break;
         case IPresentablePart.PROP_HIGHLIGHT_IF_BACK:
             // FontRegistry registry =
 // PlatformUI.getWorkbench().
 // getThemeManager().getCurrentTheme().
 // getFontRegistry();
 //
 // if(!getCurrent().equals(part))//Set bold if it does currently
 // have focus
 // tab.setFont(registry.getBold(IWorkbenchThemeConstants.TAB_TEXT_FONT));
 // break;
 case IPresentablePart.PROP_TOOLBAR:
         case IPresentablePart.PROP_PANE_MENU:
         case IPresentablePart.PROP_TITLE:
             setControlSize();
             break;
         }
     }

     protected final IPresentablePart getPartForTab(CTabItem item) {
         IPresentablePart part = (IPresentablePart) item.getData(TAB_DATA);

         return part;
     }

     /**
      * Returns the underlying tab folder for this presentation.
      *
      * @return
      */
     protected R21PaneFolder getPaneFolder() {
         return paneFolder;
     }

     /**
      * Returns true iff the underlying tab folder has been disposed.
      *
      * @return
      */
     public boolean isDisposed() {
         return paneFolder == null || paneFolder.isDisposed();
     }

     /**
      * Update the tab folder's colours to match the current theme settings and
      * active state
      */
     protected void updateGradient() {

         if (isDisposed()) {
             return;
         }

         Color fgColor;
         Color[] bgColors;
         int[] bgPercents;
         boolean vertical = false;
         if (isActive()) {
             if (getShellActivated()) {
                 fgColor = R21Colors.getSystemColor(SWT.COLOR_TITLE_FOREGROUND);
                 bgColors = R21Colors.getActiveViewGradient();
                 bgPercents = R21Colors.getActiveViewGradientPercents();
             } else {
                 fgColor = R21Colors
                         .getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND);
                 bgColors = R21Colors.getDeactivatedViewGradient();
                 bgPercents = R21Colors.getDeactivatedViewGradientPercents();
             }

         } else {
             fgColor = R21Colors.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
             bgColors = null;
             bgPercents = null;
         }

         drawGradient(fgColor, bgColors, bgPercents, vertical);

         // Color fgColor;
 // ITheme currentTheme =
 // PlatformUI.getWorkbench().getThemeManager().getCurrentTheme();
 // FontRegistry fontRegistry = currentTheme.getFontRegistry();
 // ColorRegistry colorRegistry = currentTheme.getColorRegistry();
 // Color [] bgColors = new Color[2];
 // int [] percent = new int[1];
 // boolean vertical;

         // if (isActive()){
 //
 // CTabItem item = getPaneFolder().getSelection();
 // if(item != null && !getPartForTab(item).isBusy()){
 // Font tabFont =
 // fontRegistry.get(IWorkbenchThemeConstants.TAB_TEXT_FONT);
 // // item.setFont(tabFont);
 // }
 //
 // fgColor =
 // colorRegistry.get(IWorkbenchThemeConstants.ACTIVE_TAB_TEXT_COLOR);
 // bgColors[0] =
 // colorRegistry.get(IWorkbenchThemeConstants.ACTIVE_TAB_BG_START);
 // bgColors[1] =
 // colorRegistry.get(IWorkbenchThemeConstants.ACTIVE_TAB_BG_END);
 // percent[0] =
 // currentTheme.getInt(IWorkbenchThemeConstants.ACTIVE_TAB_PERCENT);
 // vertical =
 // currentTheme.getBoolean(IWorkbenchThemeConstants.ACTIVE_TAB_VERTICAL);
 // } else {
 // fgColor =
 // colorRegistry.get(IWorkbenchThemeConstants.INACTIVE_TAB_TEXT_COLOR);
 // bgColors[0] =
 // colorRegistry.get(IWorkbenchThemeConstants.INACTIVE_TAB_BG_START);
 // bgColors[1] =
 // colorRegistry.get(IWorkbenchThemeConstants.INACTIVE_TAB_BG_END);
 // percent[0] =
 // currentTheme.getInt(IWorkbenchThemeConstants.INACTIVE_TAB_PERCENT);
 // vertical =
 // currentTheme.getBoolean(IWorkbenchThemeConstants.INACTIVE_TAB_VERTICAL);
 // }
 //
 //
 // drawGradient(fgColor, bgColors, bgPercents, false);
 }

     /**
      * Draws the applicable gradient on the title area
      *
      * @param fgColor
      * @param bgColors
      * @param percentages
      * @param vertical
      */
     public void drawGradient(Color fgColor, Color[] bgColors,
             int[] percentages, boolean vertical) {
         // paneFolder.setSelectionForeground(fgColor);
 // paneFolder.setSelectionBackground(bgColors, percentages, vertical);

         if (titleLabel == null || viewToolBar == null) {
             return;
         }

         titleLabel.setBackground(bgColors, percentages, vertical);
         titleLabel.setForeground(fgColor);

         titleLabel.update();
     }

     public boolean isActive() {
         return activeState;
     }

     /**
      * Set the size of a page in the folder.
      *
      * TODO: Kim here...I had to make this public so that the when the font was
      * updated via the color scheme service it could relayout the
      * presentation... calling control.getLayout() doesn't do the trick.
      */
     public void setControlSize() {
         // Set up the top-right controls
 // List topRight = new ArrayList(3);

         if (current != null) {
             paneFolder.setTopLeft(titleLabel);
             titleLabel.setText(current.getTitle());
             titleLabel.setImage(current.getTitleImage());
             titleLabel.setVisible(true);

             // set tooltip (https://bugs.eclipse.org/bugs/show_bug.cgi?id=67513)
 String toolTipText = current.getTitleToolTip();
             titleLabel.setToolTipText(toolTipText
                     .equals(Util.ZERO_LENGTH_STRING) ? null : toolTipText);
             
         }

         Control currentToolbar = getCurrentToolbar();
         paneFolder.setTopCenter(currentToolbar);

         IPartMenu partMenu = getPartMenu();

         if (partMenu != null) {
             pullDownButton.setEnabled(true);
         } else {
             pullDownButton.setEnabled(false);
         }
         paneFolder.setTopRight(viewToolBar);
         viewToolBar.setVisible(true);

         paneFolder.layout(true);

         if (current != null) {
             Rectangle clientArea = paneFolder.getClientArea();
             Rectangle bounds = paneFolder.getControl().getBounds();
             clientArea.x += bounds.x;
             clientArea.y += bounds.y;

             current.setBounds(clientArea);
         }

     }

     /**
      * Returns the IPartMenu for the currently selected part, or null if the
      * current part does not have a menu.
      *
      * @return the IPartMenu for the currently selected part or null if none
      */
     protected IPartMenu getPartMenu() {
         IPresentablePart part = getCurrentPart();
         if (part == null) {
             return null;
         }

         return part.getMenu();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.Presentation#dispose()
      */
     public void dispose() {
         if (isDisposed()) {
             return;
         }

         // remove shell listener
 paneFolder.getControl().getShell().removeShellListener(shellListener);

         PresentationUtil.removeDragListener(paneFolder.getControl(),
                 dragListener);
         PresentationUtil.removeDragListener(titleLabel, dragListener);

         systemMenuManager.dispose();
         systemMenuManager.removeAll();
         paneFolder.getControl().dispose();
         paneFolder = null;

         titleLabel.dispose();
         titleLabel = null;

         viewToolBar.dispose();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.Presentation#setActive(boolean)
      */
     public void setActive(boolean isActive) {
         activeState = isActive;
         updateGradient();
     }

     /**
      * Return whether the window's shell is activated
      */
     /* package */boolean getShellActivated() {
         return shellActive;
     }

     /**
      * Returns the top level window.
      */
     public Window getWindow() {
         Control ctrl = getControl();
         if (ctrl != null) {
             Object data = ctrl.getShell().getData();
             if (data instanceof Window) {
                 return (Window) data;
             }
         }
         return null;
     }

     private CTabItem createPartTab(IPresentablePart part, int tabIndex) {
         CTabItem tabItem;

         int style = SWT.NONE;

         if (getSite().isCloseable(part)) {
             style |= SWT.CLOSE;
         }

         tabItem = paneFolder.createItem(style, tabIndex);

         tabItem.setData(TAB_DATA, part);

         part.addPropertyListener(childPropertyChangeListener);
         tabItem.addDisposeListener(tabDisposeListener);

         initTab(tabItem, part);

         return tabItem;
     }

     // Create a close button in the title bar for the argument part (if needed).
 private void updateCloseButton() {
         // remove the close button if needed
 if (current == null || !getSite().isCloseable(current)) {
             if (closeButton != null) {
                 closeButton.dispose();
                 closeButton = null;

                 paneFolder.flush();
             }
             return;
         }

         // a close button is needed, so if its already there, we're done
 if (closeButton != null) {
             return;
         }

         // otherwise create it
 closeButton = new ToolItem(viewToolBar, SWT.PUSH);
         closeButton.setDisabledImage(null);
         closeButton.setImage(WorkbenchImages
                 .getImage(IWorkbenchGraphicConstants.IMG_LCL_CLOSE_VIEW));
         closeButton.setToolTipText(R21PresentationMessages
                 .getString("BasicStackPresentation.close.tooltip")); //$NON-NLS-1$
 closeButton.addSelectionListener(new SelectionAdapter() {
             public void widgetSelected(SelectionEvent e) {
                 close(getCurrent());
             }
         });

         paneFolder.flush();
     }

     /**
      * Initializes a tab for the given part. Sets the text, icon, tool tip, etc.
      * This will also be called whenever a relevant property changes in the part
      * to reflect those changes in the tab. Subclasses may override to change
      * the appearance of tabs for a particular part.
      *
      * @param tabItem
      * tab for the part
      * @param part
      * the part being displayed
      */
     protected void initTab(CTabItem tabItem, IPresentablePart part) {
         tabItem.setText(part.getName());

         // tabItem.setImage(part.getTitleImage());

         // String toolTipText = part.getTitleToolTip();
 // if (!toolTipText.equals(Util.ZERO_LENGTH_STRING)) {
 // tabItem.setToolTipText(toolTipText);
 // }

         // FontRegistry registry =
 // PlatformUI.getWorkbench().
 // getThemeManager().getCurrentTheme().
 // getFontRegistry();
 //
 // if(part.isBusy())
 // tabItem.setFont(registry.getItalic(IWorkbenchThemeConstants.TAB_TEXT_FONT));
 // else{
 // tabItem.setFont(registry.get(IWorkbenchThemeConstants.TAB_TEXT_FONT));
 // }

     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.StackPresentation#addPart(org.eclipse.ui.internal.skins.IPresentablePart,
      * org.eclipse.ui.internal.skins.IPresentablePart)
      */
     public void addPart(IPresentablePart newPart, Object cookie) {

         int idx;

         if (cookie instanceof Integer ) {
             idx = ((Integer ) cookie).intValue();
         } else {
             // Select a location for newly inserted parts
 idx = paneFolder.getItemCount();
         }

         addPart(newPart, idx);
     }

     /**
      * Adds the given presentable part to this presentation at the given index.
      * Does nothing if a tab already exists for the given part.
      *
      * @param newPart
      * @param index
      */
     public void addPart(IPresentablePart newPart, int index) {
         // If we already have a tab for this part, do nothing
 if (getTab(newPart) != null) {
             return;
         }
         createPartTab(newPart, index);

         setControlSize();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.StackPresentation#removePart(org.eclipse.ui.internal.skins.IPresentablePart)
      */
     public void removePart(IPresentablePart oldPart) {
         if (current == oldPart) {
             titleLabel.setImage(null);
             current = null;
         }

         CTabItem item = getTab(oldPart);
         if (item == null) {
             return;
         }
         oldPart.setVisible(false);

         item.dispose();

         // Layout the folder again in case there is only one item
 setControlSize();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.StackPresentation#selectPart(org.eclipse.ui.internal.skins.IPresentablePart)
      */
     public void selectPart(IPresentablePart toSelect) {
         if (toSelect == current) {
             return;
         }

         IPresentablePart oldPart = current;

         current = toSelect;

         if (current != null) {
             paneFolder.setSelection(indexOf(current));
             current.setVisible(true);
             updateCloseButton();
             setControlSize();
         }

         if (oldPart != null) {
             oldPart.setVisible(false);
         }
     }

     public IPresentablePart getCurrentPart() {
         return current;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.Presentation#setBounds(org.eclipse.swt.graphics.Rectangle)
      */
     public void setBounds(Rectangle bounds) {
         if (getSite().getState() == IStackPresentationSite.STATE_MINIMIZED) {
             bounds = Geometry.copy(bounds);
             bounds.height = computePreferredSize(false, Integer.MAX_VALUE,
                     bounds.width, Integer.MAX_VALUE);
         }

         paneFolder.getControl().setBounds(bounds);
         setControlSize();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.Presentation#computeMinimumSize()
      */
     public Point computeMinimumSize() {
         Point result = Geometry.getSize(paneFolder.computeTrim(0, 0, 0, 0));

         result.x += 100;

         return result;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.Presentation#setVisible(boolean)
      */
     public void setVisible(boolean isVisible) {
         if (current != null) {
             current.setVisible(isVisible);
         }
         paneFolder.getControl().setVisible(isVisible);
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.Presentation#setState(int)
      */
     public void setState(int state) {
         // tabFolder.setState(state);
 }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.Presentation#getSystemMenuManager()
      */
     public IMenuManager getSystemMenuManager() {
         return systemMenuManager;
     }

     /**
      * @param point
      */
     protected void showSystemMenu(Point point) {
         Menu aMenu = systemMenuManager.createContextMenu(paneFolder
                 .getControl().getParent());
         systemMenuManager.update(true);
         aMenu.setLocation(point.x, point.y);
         aMenu.setVisible(true);
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.Presentation#getControl()
      */
     public Control getControl() {
         return paneFolder.getControl();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.internal.skins.StackPresentation#dragOver(org.eclipse.swt.widgets.Control,
      * org.eclipse.swt.graphics.Point)
      */
     public StackDropResult dragOver(Control currentControl, Point location) {

         // Determine which tab we're currently dragging over
 Point localPos = paneFolder.getControl().toControl(location);
         final CTabItem tabUnderPointer = paneFolder.getItem(localPos);

         // This drop target only deals with tabs... if we're not dragging over
 // a tab, exit.
 if (tabUnderPointer == null) {
             return null;
         }

         // workaround when left tab is dragged over next
 int dragOverIndex = paneFolder.indexOf(tabUnderPointer);

        return new StackDropResult(Geometry.toDisplay(paneFolder.getControl(),
                tabUnderPointer.getBounds()), new Integer (dragOverIndex));
    }

    /**
     * Returns the toolbar control for the currently selected part, or null if
     * none (not all parts have a toolbar).
     *
     * @return the current toolbar or null if none
     */
    protected Control getCurrentToolbar() {
        IPresentablePart part = getCurrentPart();
        if (part == null) {
            return null;
        }

        return part.getToolBar();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.presentations.StackPresentation#showSystemMenu()
     */
    public void showSystemMenu() {
        IPresentablePart part = getCurrentPart();
        if (part != null) {
            Rectangle bounds = DragUtil.getDisplayBounds(paneFolder
                    .getControl());

            int idx = paneFolder.getSelectionIndex();
            if (idx > -1) {
                CTabItem item = paneFolder.getItem(idx);
                Rectangle itemBounds = item.getBounds();

                bounds.x += itemBounds.x;
                bounds.y += itemBounds.y;
            }

            Point location = new Point(bounds.x, bounds.y
                    + paneFolder.getTabHeight());
            showSystemMenu(location);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.presentations.StackPresentation#getTabList(IPresentablePart)
     */
    public Control[] getTabList(IPresentablePart part) {
        ArrayList list = new ArrayList ();
        if (paneFolder.getTabPosition() == SWT.BOTTOM) {
            if (part.getToolBar() != null) {
                list.add(part.getToolBar());
            }
            if (part.getControl() != null) {
                list.add(part.getControl());
            }
            if (getPaneFolder() != null) {
                list.add(getPaneFolder().getControl());
            }
        } else {
            if (getPaneFolder() != null) {
                list.add(getPaneFolder().getControl());
            }
            if (part.getToolBar() != null) {
                list.add(part.getToolBar());
            }
            if (part.getControl() != null) {
                list.add(part.getControl());
            }
        }
        return (Control[]) list.toArray(new Control[list.size()]);
    }

    protected void showList(Shell parentShell, int x, int y) {
        // final R21PaneFolder tabFolder = getTabFolder();
 //
 // int shellStyle = SWT.RESIZE | SWT.ON_TOP | SWT.NO_TRIM;
 // int tableStyle = SWT.V_SCROLL | SWT.H_SCROLL;
 // final BasicStackList editorList = new
 // BasicStackList(tabFolder.getControl().getShell(),
 // shellStyle, tableStyle);
 // editorList.setInput(this);
 // Point size = editorList.computeSizeHint();
 //
 // Rectangle bounds = Display.getCurrent().getBounds();
 // if (x + size.x > bounds.width) x = bounds.width - size.x;
 // if (y + size.y > bounds.height) y = bounds.height - size.y;
 // editorList.setLocation(new Point(x, y));
 // editorList.setVisible(true);
 // editorList.setFocus();
 // editorList.getTableViewer().getTable().getShell().addListener(
 // SWT.Deactivate, new Listener() {
 //
 // public void handleEvent(Event event) {
 // editorList.setVisible(false);
 // }
 // });
 }

    /*
     * Shows the list of tabs at the top left corner of the editor
     */
    protected void showListDefaultLocation() {
        R21PaneFolder tabFolder = getPaneFolder();
        Shell shell = tabFolder.getControl().getShell();
        Rectangle clientArea = tabFolder.getClientArea();
        Point location = tabFolder.getControl().getDisplay().map(
                tabFolder.getControl(), null, clientArea.x, clientArea.y);
        showList(shell, location.x, location.y);
    }

    void setSelection(CTabItem tabItem) {
        getSite().selectPart(getPartForTab(tabItem));
    }

    void close(IPresentablePart presentablePart) {
        getSite().close(new IPresentablePart[] { presentablePart });
    }

    Image getLabelImage(IPresentablePart presentablePart) {
        return presentablePart.getTitleImage();
    }

    String getLabelText(IPresentablePart presentablePart, boolean includePath) {
        String title = presentablePart.getTitle().trim();
        return title;
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.presentations.StackPresentation#setActive(int)
     */
    public void setActive(int newState) {
        setActive(newState == AS_ACTIVE_FOCUS);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.presentations.StackPresentation#restoreState(org.eclipse.ui.presentations.IPresentationSerializer,
     * org.eclipse.ui.IMemento)
     */
    public void restoreState(IPresentationSerializer serializer,
            IMemento savedState) {
        IMemento[] parts = savedState.getChildren(IWorkbenchConstants.TAG_PART);

        for (int idx = 0; idx < parts.length; idx++) {
            String id = parts[idx].getString(IWorkbenchConstants.TAG_ID);

            if (id != null) {
                IPresentablePart part = serializer.getPart(id);

                if (part != null) {
                    addPart(part, getPaneFolder().getItemCount());
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.presentations.StackPresentation#saveState(org.eclipse.ui.presentations.IPresentationSerializer,
     * org.eclipse.ui.IMemento)
     */
    public void saveState(IPresentationSerializer context, IMemento memento) {
        super.saveState(context, memento);

        List parts = getPresentableParts();

        Iterator iter = parts.iterator();
        while (iter.hasNext()) {
            IPresentablePart next = (IPresentablePart) iter.next();

            IMemento childMem = memento
                    .createChild(IWorkbenchConstants.TAG_PART);
            childMem.putString(IWorkbenchConstants.TAG_ID, context.getId(next));
        }
    }

    /**
     * Returns the List of IPresentablePart currently in this presentation
     */
    private List getPresentableParts() {
        Assert.isTrue(!isDisposed());

        CTabItem[] items = getPaneFolder().getItems();
        List result = new ArrayList (items.length);

        for (int idx = 0; idx < getPaneFolder().getItemCount(); idx++) {
            result.add(getPartForTab(items[idx]));
        }

        return result;
    }
}

